import os
import sys
import datetime

import PDBConst
from metadata import PDBConfig

from importlib.machinery import SourceFileLoader

# Parse params
c_pdbCmdMysql = PDBConfig.pdbCmdMysql
c_pdbCmdMysqldump = PDBConfig.pdbCmdMysqldump
c_pdbCmd7z = PDBConfig.pdbCmd7z
c_pdbFileInitDB = PDBConfig.pdbFileInitDB
c_pdbFileDropDB = PDBConfig.pdbFileDropDB
c_pdbFileInitDBShell = PDBConfig.pdbFileInitDBShell
c_pdbFileBackupDBShell = PDBConfig.pdbFileBackupDBShell
c_pdbFileRestoreDBShell = PDBConfig.pdbFileRestoreDBShell
c_pdbDefinitionPath = PDBConfig.pdbDefinitionPath
c_pdbDirGenerated = PDBConfig.pdbDirGenerated
c_pdbDirBackup = PDBConfig.pdbDirBackup
c_pdbDirSchema = PDBConfig.pdbDirSchema
paramOptions = [
    "-pdbCmdMysql",
    "-pdbCmdMysqldump",
    "-pdbCmd7z",
    "-pdbFileInitDB",
    "-pdbFileDropDB",
    "-pdbFileInitDBShell",
    "-pdbFileBackupDBShell",
    "-pdbFileRestoreDBShell",
    "-pdbDefinitionPath",
    "-pdbDirGenerated",
    "-pdbDirBackup",
    "-pdbDirSchema"
]
paramIndex = 1
paramLen = len(sys.argv)
while paramIndex < paramLen:
    option = sys.argv[paramIndex]
    if option not in paramOptions:
        exit("Wrong option: " + option)
    if paramIndex + 1 >= paramLen:
        exit("No param for option: " + option)
    value = sys.argv[paramIndex + 1]
    exec(option.replace("-", "c_") + " = \"" + value + "\"")
    paramIndex += 2

# Load schema module
if not os.path.isdir(c_pdbDirSchema):
    exit("Invalid schema module dir: " + c_pdbDirSchema)
checkerPath = os.path.join(c_pdbDirSchema, "SchemaChecker.py")
checkerModule = SourceFileLoader("SchemaChecker", checkerPath).load_module()
checkerClass = getattr(checkerModule, "SchemaChecker")

pdbDirBase = os.path.split(os.path.realpath(__file__))[0]

# Check database definition schema first
schemaPath = os.path.join(pdbDirBase, "PDBSchema.py")
dbDefinitionPath = c_pdbDefinitionPath
constPath = os.path.join(pdbDirBase, "PDBConst.py")
configChecker = checkerClass(dbDefinitionPath, schemaPath, constPath)
configCheckResult, schema = configChecker.Check()
if not configCheckResult:
    exit("PDB schema check error!")

# Generate DB drop script
dbDropScriptPath = os.path.join(c_pdbDirGenerated, c_pdbFileDropDB)
dbDropScript = open(dbDropScriptPath, "w")
for db in schema:
    dbDropScript.write("drop database " + db[PDBConst.Name] + ";\n")
dbDropScript.close()

#
# Generate DB init script
#

dbInitScriptPath = os.path.join(c_pdbDirGenerated, c_pdbFileInitDB)
dbInitScript = open(dbInitScriptPath, "w")

# First create DB
for db in schema:
    dbInitScript.write("## Create Database " + db[PDBConst.Name] + " ##\n")
    dbInitScript.write("create database " + db[PDBConst.Name] + ";\n")
    dbInitScript.write("use " + db[PDBConst.Name] + ";\n")
    dbInitScript.write("\n")
    
    # Then create table 
    for table in db[PDBConst.Tables]:
        dbInitScript.write("## Create Table " + table[PDBConst.Name] + " ##\n")
        dbInitScript.write("create table " + table[PDBConst.Name] + " (\n")

        # Handle "PRIMARY KEY" first
        primaryKeys = None
        if PDBConst.PrimaryKey in table:
            primaryKeys = table[PDBConst.PrimaryKey]
            del table[PDBConst.PrimaryKey]
        
        # Add column description
        index = len(table[PDBConst.Columns])
        for column in table[PDBConst.Columns]:
            index = index - 1
            if len(column[PDBConst.Attributes]) > 1:
                dbInitScript.write("    " +
                                   column[PDBConst.Name] +
                                   " " +
                                   " ".join(column[PDBConst.Attributes]))
            else:
                dbInitScript.write("    " +
                                   column[PDBConst.Name] +
                                   " " +
                                   column[PDBConst.Attributes][0])
            if index == 0:
                if primaryKeys is not None:
                    dbInitScript.write(",\n")
                    dbInitScript.write("    PRIMARY KEY(" + ", ".join(primaryKeys) + ")")
                dbInitScript.write(");\n")
            else:
                dbInitScript.write(",\n")

        # Insert initial values
        if PDBConst.Initials not in table:
            continue
        for row in  table[PDBConst.Initials]:
            columns = ", ".join(row.keys())
            value = ", ".join(row.values())
            dbInitScript.write("insert into " + table[PDBConst.Name] + " (" + columns + ") values (" + value + ");\n")
                               
        dbInitScript.write("\n")
    dbInitScript.write("\n")                               
                               
dbInitScript.close()

# Generate init shell script for MySQL
dbInitShellPath = os.path.join(c_pdbDirGenerated, c_pdbFileInitDBShell)
dbInitShell = open(dbInitShellPath, "w")
dbInitShell.write("# Usage: sh " + dbInitShellPath + " DB_USERNAME\n")
dbInitShell.write("if test $# -lt 1\n")
dbInitShell.write("then\n")
dbInitShell.write("    echo \"sh " + c_pdbFileInitDBShell + " DB_USERNAME\"\n")
dbInitShell.write("    exit\n")
dbInitShell.write("fi\n")
dropCommand = c_pdbCmdMysql + " -u $1 -p < " + dbDropScriptPath
dbInitShell.write(dropCommand + "\n")
dbInitShell.write("echo \"" + dropCommand + "\"\n");
initCommand = c_pdbCmdMysql + " -u $1 -p < " + dbInitScriptPath
dbInitShell.write(initCommand + "\n")
dbInitShell.write("echo \"" + initCommand + "\"\n")
dbInitShell.close()

# Generate DB backup shell script
dbBackupShellPath = os.path.join(c_pdbDirGenerated, c_pdbFileBackupDBShell)
dbBackupShell = open(dbBackupShellPath, "w")
dbBackupShell.write("# Usage: sh " + dbBackupShellPath + " DB_USERNAME DB_NAME 7zPW DBPW\n")
dbBackupShell.write("if test $# -lt 4\n")
dbBackupShell.write("then\n")
dbBackupShell.write("    echo \"" + c_pdbFileBackupDBShell + " DB_USERNAME DB_NAME 7zPW DBPW\"\n")
dbBackupShell.write("    exit\n")
dbBackupShell.write("fi\n")
dbBackupFilePath = os.path.join(c_pdbDirBackup, "$2_$(date +'%Y%m%d').bak")
backupCommand = c_pdbCmdMysqldump + " -u $1 --password=$4 $2 > " + dbBackupFilePath
dbBackupShell.write(backupCommand + "\n")
dbBackupShell.write("echo \"" + backupCommand + "\"\n");
dbBackupShell.write(c_pdbCmd7z + " a -p$3 " +
                    dbBackupFilePath.replace(".bak", ".7z") +
                    " " +
                    dbBackupFilePath +
                    "\n")
dbBackupShell.write("rm -rf " + dbBackupFilePath + "\n")
dbBackupShell.close()

# Generate DB restore shell script
dbRestoreShellPath = os.path.join(c_pdbDirGenerated, c_pdbFileRestoreDBShell)
dbRestoreShell = open(dbRestoreShellPath, "w")
dbRestoreShell.write("# Usage: sh " + dbRestoreShellPath + " DB_USERNAME DB_NAME BAK_FILE_NAME\n")
dbRestoreShell.write("if test $# -lt 3\n")
dbRestoreShell.write("then\n")
dbRestoreShell.write("    echo \"" +
                     c_pdbFileRestoreDBShell +
                     " DB_USERNAME DB_NAME BAK_FILE_NAME\"\n")
dbRestoreShell.write("    exit\n")
dbRestoreShell.write("fi\n")
dbRestoreFilePath = os.path.join(c_pdbDirBackup, "$3")
dbRestoreShell.write("dbBakFile=`echo " + dbRestoreFilePath + " | sed -e 's/.7z/.bak/'`\n")
dbRestoreShell.write("cd " + c_pdbDirBackup + "\n")
dbRestoreShell.write(c_pdbCmd7z + " e " + dbRestoreFilePath + "\n")
restoreCommand = c_pdbCmdMysql + " -u $1 -p $2 < $dbBakFile"
dbRestoreShell.write(restoreCommand + "\n")
dbRestoreShell.write("echo \"" + restoreCommand + "\"\n");
dbRestoreShell.write("rm -rf $dbBakFile\n")
dbRestoreShell.close()
